﻿using System;
using System.Net;

using System.Diagnostics;
using System.Threading;

using System.Net.Security;
using System.Security.Principal;

namespace negoserverjni
{
    public class LoginAuthentication
    {
        internal static TraceSource log = new TraceSource("LoginAuthentication");
        public string NameOfLogin(string userName, string password)
        {
            WindowsIdentity id = DoLogin(userName, password);
            if (id != null) return id.Name;
            return null;
        }

        public WindowsIdentity DoLogin(string userName, string password)
        {
            return DoLoginWithOneThread(userName, "", password);
        }

        public WindowsIdentity DoLoginWithOneThread(string userName, string domain, string password)
        {
            if (userName == null || password == null || domain == null) return null;
            try
            {
                int id = Thread.CurrentThread.ManagedThreadId;
                NetworkCredential cred;

                if (domain != "")
                {
                    cred = new NetworkCredential(userName, password, domain);
                }
                else
                {
                    int index = userName.IndexOf('\\');
                    if (index != -1)
                    {
                        domain = userName.Substring(0, index);
                        userName = userName.Substring(index + 1);
                        cred = new NetworkCredential(userName, password, domain);
                    }
                    else cred = new NetworkCredential(userName, password);
                }
                log.TraceEvent(TraceEventType.Verbose,Thread.CurrentThread.ManagedThreadId,"userName " + userName);
                log.TraceEvent(TraceEventType.Verbose,Thread.CurrentThread.ManagedThreadId,"domain " + domain);
                log.TraceEvent(TraceEventType.Verbose,Thread.CurrentThread.ManagedThreadId,"password ******");
                using (State state = new State())
                {
                    PseudoStream pseudo = new PseudoStream(state);
                    state.Pseudo = pseudo;
                    using (NegotiateStream clientside = new NegotiateStream(pseudo, true))
                    {
                        log.TraceEvent(TraceEventType.Verbose,Thread.CurrentThread.ManagedThreadId,"Before BeginAuthenticateAsClient");
                        IAsyncResult ar = clientside.BeginAuthenticateAsClient(cred, "", ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification, null, null);
                        log.TraceEvent(TraceEventType.Verbose,Thread.CurrentThread.ManagedThreadId,"After BeginAuthenticateAsClient");


                        for (var continuation = state.Continuation; continuation != null; continuation = state.Continuation)
                        {
                            log.TraceEvent(TraceEventType.Verbose, Thread.CurrentThread.ManagedThreadId, "Before Continuation of BeginWrite");
                            continuation(state.ParamContinuation);
                        }

                        log.TraceEvent(TraceEventType.Verbose, Thread.CurrentThread.ManagedThreadId, "After last continuation");
                        
                        clientside.EndAuthenticateAsClient(ar);
                        log.TraceEvent(TraceEventType.Verbose,Thread.CurrentThread.ManagedThreadId,"After EndAuthenticateAsClient");


                        if (state.Identity != null)
                        {
                            log.TraceEvent(TraceEventType.Verbose,Thread.CurrentThread.ManagedThreadId,"state.Identity != null " + state.Identity.Name);
                            WindowsIdentity identity = state.Identity;
                            return identity;
                        }
                        else
                        {
                            log.TraceEvent(TraceEventType.Verbose,Thread.CurrentThread.ManagedThreadId,"state.Identity is null");
                            return null;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                log.TraceEvent(TraceEventType.Verbose, Thread.CurrentThread.ManagedThreadId, e.GetType() + " : " + e.Message);
                if (e.InnerException != null) log.TraceEvent(TraceEventType.Verbose,Thread.CurrentThread.ManagedThreadId,e.InnerException.GetType() + " : " + e.InnerException.Message);
                return null;
            }
        }
    }
         

}
